from hashlib import new
from operator import imod
from re import L
from time import sleep
from sqlalchemy import null
from sqlalchemy import and_
import datetime
from app.api import get_value, set_value
from app.api.memory_class import ChargingPileState, AllCarInformation
from app.models import UserInformation, ChargingDetail, ChargingPileReport
from app import db


# 根据user_id获得用户的姓名信息
def id_to_name(user_id):
    try:
        temp = UserInformation.query.filter(
            UserInformation.user_id == user_id).first()
        return temp.user_name
    except:
        return ""

# 根据user_name获得用户的姓名信息


def name_to_id(user_name):
    try:
        temp = UserInformation.query.filter(
            UserInformation.user_name == user_name).first()
        return temp.user_id
    except:
        return 0

# 根据开始时间和结束时间计算充电费用,返回充电费用


def cost_of_charging(starting_time: datetime.datetime, stopping_time: datetime.datetime, pattern):
    # print(datetime.datetime.now(),"  ",starting_time)
    # print(datetime.datetime.now(),"  ",stopping_time)
    over_day = stopping_time.day-starting_time.day
    if pattern == "F":
        unit_speed = get_value("F_speed")/3600
    elif pattern == "T":
        unit_speed = get_value("T_speed")/3600
    total_cost = 0
    # total_charge = 0
    ls_start = []
    for i in get_value("time_quantum"):
        temp_time = datetime.datetime.strptime(
            str(starting_time.date()) + i, '%Y-%m-%d%H:%M')
        ls_start.append(temp_time)

    temp_time = datetime.datetime.strptime(
        str(starting_time.date()+datetime.timedelta(days=1)) + '0:00', '%Y-%m-%d%H:%M')
    ls_start.append(temp_time)

    ls_stop = []
    for i in get_value("time_quantum"):
        temp_time = datetime.datetime.strptime(
            str(stopping_time.date()) + i, '%Y-%m-%d%H:%M')
        ls_stop.append(temp_time)

    temp_time = datetime.datetime.strptime(
        str(stopping_time.date()+datetime.timedelta(days=1)) + '0:00', '%Y-%m-%d%H:%M')
    ls_stop.append(temp_time)

    ls_cost = get_value("time_quantum_cost")
    length = len(ls_cost)
    if over_day == 0:  # 在同一天
        for i in range(length):
            if (starting_time >= ls_start[i] and starting_time <= ls_start[i+1]):
                start = i
            if (stopping_time >= ls_start[i] and stopping_time <= ls_start[i+1]):
                stop = i
        if start == stop:  # 在同一个时间段内
            total_cost += (stopping_time-starting_time).seconds * \
                unit_speed*ls_cost[start]
            # total_charge += (stopping_time-starting_time).seconds * unit_speed
            return total_cost
        # 如果不在一个时间段内
        # 先计算首尾
        total_cost += (ls_start[start+1] -
                       starting_time).seconds * unit_speed * ls_cost[start]
        # total_charge += (ls_start[start+1] -starting_time).seconds * unit_speed
        total_cost += (stopping_time -
                       ls_start[stop]).seconds * unit_speed * ls_cost[stop]
        # total_charge += (stopping_time-ls_start[stop]).seconds * unit_speed
        # 再计算中间的整时间段
        for i in range(start+1, stop):
            total_cost += (ls_start[i+1]-ls_start[i]
                           ).seconds * unit_speed * ls_cost[i]
            # total_charge += (ls_start[i+1]-ls_start[i]).seconds * unit_speed
        return total_cost
    else:  # 不在同一天
        for i in range(length):
            if (starting_time >= ls_start[i] and starting_time <= ls_start[i+1]):
                start = i
            if (stopping_time >= ls_stop[i] and stopping_time <= ls_stop[i+1]):
                stop = i
        # 先计算开头和结尾的单独两天
        total_cost += (ls_start[start+1] -
                       starting_time).seconds * unit_speed * ls_cost[start]
        # total_charge += (ls_start[start+1] -starting_time).seconds * unit_speed
        total_cost += (stopping_time -
                       ls_stop[stop]).seconds * unit_speed * ls_cost[stop]
        # total_charge += (stopping_time-ls_stop[stop]).seconds * unit_speed
        # print(datetime.datetime.now(),"  ",start)
        for i in range(start+1, length):
            total_cost += (ls_start[i+1]-ls_start[i]
                           ).seconds * unit_speed * ls_cost[i]
            # total_charge += (ls_start[i+1]-ls_start[i]).seconds * unit_speed
        for i in range(0, stop):
            total_cost += (ls_stop[i+1]-ls_stop[i]
                           ).seconds * unit_speed * ls_cost[i]
            # total_charge += (ls_stop[i+1]-ls_stop[i]).seconds * unit_speed
        # 然后直接加上中间的所有整数天
        day_charge = unit_speed*60*60*24
        day_cost = get_value("day_cost")*unit_speed*60*60
        total_cost += day_cost*(over_day-1)
        # total_charge += day_charge*(over_day-1)
        return total_cost


# 检查用户是否已经登录,未登录返回0,已登录返回用户的id
def check_log_in(name):
    list_temp = (get_value("user_log_in"))
    for i in list_temp:
        if i["user_name"] == name:
            return i["user_id"]
    return 0


# 注册,成功返回用户id,失败返回0
def sign_in(name, password):
    # 首先检查名字是否有重复
    temp = UserInformation.query.filter(
        UserInformation.user_name == name).first()
    if temp:
        return 0
    user = UserInformation(
        user_name=name, user_password=password, user_permission="user")
    db.session.add(user)
    db.session.commit()
    return user.user_id


# 登录,成功返回用户id,失败返回0
def log_in(name, password):
    temp = UserInformation.query.filter(
        and_(UserInformation.user_name == name, UserInformation.user_password == password)).first()
    if temp == null:
        return 0
    list_temp = (get_value("user_log_in"))
    list_temp.append({"user_id": temp.user_id, "user_name": temp.user_name,
                     "user_permission": temp.user_permission})
    set_value("user_log_in", list_temp)
    return temp.user_id


# 充电区叫号,从等候区叫下一位车辆来充电,,修改information,返回下一个进入的车的用户id
# 充电区等候的车进入准备充电,这个步骤交给另一个函数完成#######################
# 弹出正在充电的车,这个步骤交给另一个函数完成#######################
def call_next_from_waiting(pile_id):
    pattern = ""
    if (pile_id == 1 or pile_id == 2):
        pattern = "F"
    else:
        pattern = "T"
    next_in_id = 0
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if(i.get_pattern() == pattern and i.get_state() == 3):  # 这里找到下一个进来的车
            # print(datetime.datetime.now(),"  ","next_in_id_func:", next_in_id)
            next_in_id = i.get_user_id()
            i.change_pile(pile_id)  # 修改为此充电桩
            i.change_state(2)  # 修改为充电区等待
            break
    if next_in_id != 0:
        print(datetime.datetime.now(), "  ", "call", id_to_name(next_in_id),
              "from waiting to charging area,pile id is", pile_id)
    return next_in_id


# 弹出充完电的车或者是准备充电的车,修改information,返回这个车的用户id
def pop_from_charging(pile_id, state):
    # state为4表示弹出充完电的车,state为5表示弹出准备充电的车(实际没充电)
    pattern = ""
    if (pile_id == 1 or pile_id == 2):
        pattern = "F"
    else:
        pattern = "T"
    now_charge_id = 0
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if(i.get_pattern() == pattern and i.get_state() == state and i.get_pile() == pile_id):  # 找到了这个车
            now_charge_id = i.get_user_id()
            if state == 5:
                i.change_state(6)  # 修改为取消充电
            # 完成充电的state不需要改变,依然是4
            break
    print(datetime.datetime.now(), "  ", "let", id_to_name(now_charge_id),
          "out from charging position,pile id is", pile_id)
    return now_charge_id


# 找到这个充电桩充电区等着充电的那辆车的用户id,修改information
def call_next_to_charge(pile_id):
    pattern = ""
    if (pile_id == 1 or pile_id == 2):
        pattern = "F"
    else:
        pattern = "T"
    next_charge_id = 0
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if(i.get_pattern() == pattern and i.get_state() == 2 and i.get_pile() == pile_id):  # 找到了这个车
            next_charge_id = i.get_user_id()
            i.change_state(5)  # 修改为准备充电
            break
    if next_charge_id != 0:
        print(datetime.datetime.now(), "  ", "call", id_to_name(next_charge_id),
              "to charging position,pile id is", pile_id)
    return next_charge_id


# 检查充电桩是否正常工作,1为正常工作,0为不正常工作
def check_pile_functioning(pile_id):
    charging_pile_state_list = get_value("charging_pile_state")
    for i in charging_pile_state_list:
        if(i.get_charging_pile_id() == pile_id):
            return i.get_proper_functioning()


# 寻找系统调度策略对应的那一个充电桩
def find_pile(user_name, request_charging_quantity, pattern):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return [0, 0]
    pile_all = get_value("pile_car")
    j = 0  # 充电桩编号数字
    pile_id = 0
    state = 0  # 状态
    # 先看可不可以直接去充电
    if pattern == "F":
        j = 0
        for i in [pile_all["pile1"], pile_all["pile2"]]:
            j += 1
            if(len(i) == 0 and check_pile_functioning(j)):
                # i.append(id)
                pile_id = j
                state = 5  # 准备充电
                break
    elif pattern == "T":
        j = 2
        for i in [pile_all["pile3"], pile_all["pile4"], pile_all["pile5"]]:
            j += 1
            if(len(i) == 0 and check_pile_functioning(j)):
                # i.append(id)
                pile_id = j
                state = 5  # 准备充电
                break
    # 如果不可以直接充电,就给他选择一个完成充电所需时长最短的充电桩
    # 先看充电区有没有排队剩余容量
    if pile_id == 0:
        min = 999999999
        if pattern == "F":
            j = 0
            for i in [pile_all["pile1"], pile_all["pile2"]]:
                j += 1
                if(len(i) >= 1 and len(i) < get_value("charging_space") and check_pile_functioning(j)):
                    # 需要拿到当前这个充电桩j充电车辆的启动时间,计算出已经充的电量,得到还需要充的电量
                    # 如果在ChargingDetail找不到或者拿到了但是已经完成充电，说明这辆车没有启动充电
                    try:
                        detail_temp = ChargingDetail.query.filter(
                            and_(ChargingDetail.charging_pile_id == str(j), ChargingDetail.complete == "no")).first()

                        time_pass = (datetime.datetime.now() -
                                     detail_temp.starting_time).seconds  # 已经充电的时间
                        charging_pass = time_pass * \
                            (get_value("F_speed")/3600)  # 已经充电的度数
                        target = 0

                        # car_information_list = get_value("car_information")
                        # for l in car_information_list:
                        #     if(l.get_user_id() == detail_temp.user_id and l.get_state() == 1):  # 正在充电
                        #         target = l.get_request_charging_quantity()
                        #         break
                        # new_min = request_charging_quantity + \
                        #     (target - charging_pass)

                        # 需要拿到所有这个充电桩的目标充电度数
                        car_information_list = get_value("car_information")
                        for l in car_information_list:
                            if(l.get_pile() == j and (l.get_state() == 1 or l.get_state() == 2)):  # 正在充电或者是等待
                                target += l.get_request_charging_quantity()

                        new_min = request_charging_quantity + \
                            (target - charging_pass)

                        if new_min < min:  # 更新最小
                            min = new_min
                            pile_id = j
                        state = 2
                    except:
                        new_min = 999999999  # 设置一个超大值，因为会一直等待
                        if new_min <= min:  # 更新最小
                            min = new_min
                            pile_id = j
                        state = 2
                    # if detail_temp == null:  # 没有拿到，说明那辆车并没有启动充电，只是停在那里
                    #     min = 999999999  # 设置一个超大值，因为会一直等待
                    # else:

        if pattern == "T":
            j = 2
            for i in [pile_all["pile3"], pile_all["pile4"], pile_all["pile5"]]:
                j += 1
                if(len(i) >= 1 and len(i) < get_value("charging_space") and check_pile_functioning(j)):
                    # 需要拿到当前这个充电桩j充电车辆的启动时间,计算出已经充的电量,得到还需要充的电量
                    # 如果在ChargingDetail找不到或者拿到了但是已经完成充电，说明这辆车没有启动充电
                    try:
                        # detail_temp = ChargingDetail.query.filter(
                        #     and_(ChargingDetail.charging_pile_id == str(j), ChargingDetail.complete == "no")).first()

                        # time_pass = (datetime.datetime.now() -
                        #              detail_temp.starting_time).seconds  # 已经充电的时间
                        # charging_pass = time_pass * \
                        #     (get_value("T_speed")/3600)  # 已经充电的度数
                        # target = 0
                        # # 需要拿到这辆车的目标充电度数
                        # car_information_list = get_value("car_information")
                        # for l in car_information_list:
                        #     if(l.get_user_id() == detail_temp.user_id and l.get_state() == 1):  # 正在充电
                        #         target = l.get_request_charging_quantity()
                        #         break
                        detail_temp = ChargingDetail.query.filter(
                            and_(ChargingDetail.charging_pile_id == str(j), ChargingDetail.complete == "no")).first()

                        time_pass = (datetime.datetime.now() -
                                     detail_temp.starting_time).seconds  # 已经充电的时间
                        charging_pass = time_pass * \
                            (get_value("T_speed")/3600)  # 已经充电的度数
                        target = 0

                        # 需要拿到所有这个充电桩的目标充电度数
                        car_information_list = get_value("car_information")
                        for l in car_information_list:
                            if(l.get_pile() == j and (l.get_state() == 1 or l.get_state() == 2)):  # 正在充电或者是等待
                                target += l.get_request_charging_quantity()
                        new_min = request_charging_quantity + \
                            (target - charging_pass)
                        if new_min < min:  # 更新最小
                            min = new_min
                            pile_id = j
                        state = 2
                    except:
                        new_min = 999999999  # 设置一个超大值，因为会一直等待
                        if new_min <= min:  # 更新最小
                            min = new_min
                            pile_id = j
                        state = 2
    # 还是没有找到位置
    if pile_id == 0:
        # 检查等候区是否有空余容量
        if get_value("free_space") <= 0:
            # 都没有位置
            return [-1, -1]
        else:
            set_value("free_space", get_value("free_space")-1)
            state = 3
    if pile_id != 0:
        pile_str = "pile"+str(pile_id)
        pile_all[pile_str].append(id)  # 将其加入到充电区的等待位置
    return [pile_id, state]


# 申请排队信息,未登录返回0,排队信息中已经存在它返回-1,成功返回排队号
def ask_for_line_number(user_name, total_battery_capacity, request_charging_quantity, pattern):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return [0, 0, 0]
    car_information_list = get_value("car_information")
    # 检查排队信息中是否他已经在了并且不是充完电的状态
    for i in car_information_list:
        if (i.get_user_id() == id and i.get_state() != 4):
            return [-1, -1, -1]
    # 寻找到目前最大的line_number,+1
    line_number = 0
    for i in car_information_list:
        if i.get_line_number() > line_number:
            line_number = i.get_line_number()
    line_number += 1
    # 检查对应充电模式的充电桩是否有空闲或充电区有空闲,如果有直接安排过去
    pile_all = get_value("pile_car")
    j = 0  # 充电桩编号数字
    pile_id = 0
    state = 0  # 状态
    # 寻找系统调度策略对应的那一个充电桩
    [pile_id, state] = find_pile(user_name, request_charging_quantity, pattern)
    # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
    if pile_id == -1:
        return [-1, -1, -1]
    if(pile_id != 0 and pile_id != -1):  # 让ta移动到充电区
        if (state == 5):
            print(datetime.datetime.now(), "  ", "call", user_name,
                  "to charging position,pile id is", pile_id)
        elif(state == 2):
            print(datetime.datetime.now(), "  ", "call", user_name,
                  "to charging area,pile id is", pile_id)
    elif (pile_id == -1):
        print(datetime.datetime.now(), "  ",
              "no more position in waiting area")
    elif (pile_id == 0 and state == 3):
        print(datetime.datetime.now(), "  ",
              "call", user_name, "in waiting area")
    # 加入所有车辆信息
    temp_car_information = AllCarInformation(
        id, total_battery_capacity, request_charging_quantity, datetime.datetime.now(), pattern, state, line_number, pile_id)
    car_information_list.append(temp_car_information)
    set_value("car_information", car_information_list)
    # set_value("free_space", get_value("free_space")-1)
    return [line_number, pile_id, state]


# 请求修改充电量
def change_request_charging_quantity(user_name, new_request_charging_quantity):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return 0
    # 然后看ta是不是在等候区,等候区才可以修改
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if (i.get_user_id() == id and i.get_state() == 3):
            # 找到
            i.change_request_charging_quantity(new_request_charging_quantity)
            print(datetime.datetime.now(), "  ", user_name, "change request quantity to",
                  new_request_charging_quantity)
            return 1  # 表示修改成功
    return 0  # 修改失败


# 请求修改充电模式,需要重新生成排队号,我们在原先的基础上直接对排队号修改
def change_pattern(user_name, new_pattern):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return [0, 0, 0]
    # 然后看ta是不是在等候区,等候区才可以修改
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if (i.get_user_id() == id and i.get_state() == 3):
            # 找到
            i.change_pattern(new_pattern)
            print(datetime.datetime.now(), "  ", "change",
                  user_name, "pattern to", new_pattern)
            # 寻找到目前最大的line_number,+1
            line_number = 0
            for j in car_information_list:
                if j.get_line_number() > line_number:
                    line_number = j.get_line_number()
            line_number += 1
            # 修改排队号
            i.change_line_number(line_number)
            # 接下来看新的充电模式是否可以直接充电/进入充电区等待
            pile_id = 0
            state = 0
            [pile_id, state] = find_pile(
                user_name, i.get_request_charging_quantity(), new_pattern)
            # 如果可以直接充电/进入充电区等待,我们就修改表中的state和pile_id,并返回给他安排的pile
            # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
            if(pile_id != 0 and pile_id != -1):  # 让ta移动到充电区
                i.change_pile(pile_id)
                i.change_state(state)
                set_value("free_space", get_value("free_space")+1)
                if (state == 5):
                    print(datetime.datetime.now(), "  ", "call", user_name,
                          "to charging position,pile id is", pile_id)
                elif(state == 2):
                    print(datetime.datetime.now(), "  ", "call", user_name,
                          "to charging area,pile id is", pile_id)
            elif (pile_id == -1):
                # 虽然等候区没有空余,但车辆此时就在等候区,所以不需要修改
                state = 3
                pile_id = 0
                print(datetime.datetime.now(), "  ",
                      user_name, "keep in waiting area")
            elif (pile_id == 0 and state == 3):
                set_value("free_space", get_value("free_space")+1)
                print(datetime.datetime.now(), "  ",
                      user_name, "keep in waiting area")
            # 是不是直接移动到最后一个比较好,这样寻找下一个车的时候直接从头查看就行,排队号永远是从小到大
            car_information_list.append(i)
            car_information_list.remove(i)

            return [line_number, pile_id, state]
    return [0, 0, 0]  # 修改失败


# 取消充电,充电区和等候区都可以
# 如果是等候区,就可以直接空出一个位置
# 如果是充电区等待,呼叫下一辆车进入
# 如果是一个准备充电的呢?要考虑吗?#######应该也考虑进去,这样就可以作为超时的cancel一起使用
def cancel_charging(user_name):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return 0
    # 获得下一个准备充电的车辆
    next_charge_id = 0
    # 然后看ta所处的位置
    print(datetime.datetime.now(), "  ", user_name, "cancel its charging")
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if(i.get_user_id() == id):
            state = i.get_state()
            if (state == 5):  # 准备充电
                # i.change_state(6)  # 取消充电
                pile_id = i.get_pile()  # 获得它的充电桩

                # 获得这个准备充电的车的id
                now_charge_id = 0

                now_charge_id = pop_from_charging(pile_id, state)  # 同时修改为取消充电
                if now_charge_id != 0:
                    pile_all = get_value("pile_car")
                    pile_str = "pile"+str(pile_id)
                    del(pile_all[pile_str][0])  # 弹出第一个元素
                next_charge_id = call_next_to_charge(pile_id)  # 同时修改为准备充电
                # 获得下一个进入的车辆
                next_in_id = 0
                # next_charge_id = 0
                next_in_id = call_next_from_waiting(pile_id)
                if next_in_id != 0:
                    # 修改充电桩的信息
                    pile_all = get_value("pile_car")
                    pile_str = "pile"+str(pile_id)
                    pile_all[pile_str].append(next_in_id)
                    set_value("free_space", get_value("free_space")+1)
                break
            elif(state == 3):  # 等候区等候
                i.change_state(6)  # 取消充电
                set_value("free_space", get_value(
                    "free_space")+1)  # 等候区的容量+1
                break
            elif (state == 2):  # 充电区等候
                i.change_state(6)  # 取消充电
                pile_id = i.get_pile()  # 获得它的充电桩
                # 获得下一个进入的车辆
                next_in_id = 0
                # next_charge_id = 0
                next_in_id = call_next_from_waiting(pile_id)
                # 修改充电桩的信息
                pile_all = get_value("pile_car")
                pile_str = "pile"+str(pile_id)
                pile_all[pile_str].remove(id)  # 删除原先的id
                if next_in_id != 0:
                    pile_all[pile_str].append(next_in_id)
                    set_value("free_space", get_value("free_space")+1)
                break
    return [next_charge_id, next_in_id]

# 用户选择开始充电,返回计划充电时间


def user_begin_charging(user_name):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return 0
    # 检查其state以及充电桩是否正常工作
    pile_id = 0
    car_information_list = get_value("car_information")
    # car_information = AllCarInformation()
    for i in car_information_list:
        if (i.get_user_id() == id and i.get_state() == 5):
            car_information = i
            pile_id = i.get_pile()  # 获得其充电桩编号
            break
    # 如果获得了pile_id,说明用户状态正确
    # 接下来检查充电桩状态
    pile_state = 0
    charging_pile_state_list = get_value("charging_pile_state")
    # charging_pile_state = ChargingPileState()
    for i in charging_pile_state_list:
        if(i.get_charging_pile_id() == pile_id):  # 找到充电桩
            charging_pile_state = i
            pile_state = i.get_proper_functioning()  # 获取充电桩状态
            if pile_state == 0:  # 没有正常工作
                return -1
            break
    # 检查完成,都是正确的,可以开始开启充电了
    # car_information需要更改,充电详单信息表数据库需要创建一个表项
    # 修改为在充电
    # for i in car_information_list:
    #     if (i.get_user_id() == id and i.get_state() == 5):
    #         i.change_state(1)
    car_information.change_state(1)
    pattern = ""
    if (pile_id == 0):
        return [0, 0]
    if (pile_id == 1 or pile_id == 2):
        pattern = "F"
        speed = get_value("F_speed")
    else:
        pattern = "T"
        speed = get_value("T_speed")

    charging_quantity = car_information.get_request_charging_quantity()
    charging_duration = (charging_quantity/speed)*3600  # 换算为秒

    # 创建一个新的表项
    new_detail = ChargingDetail(charging_pile_id=str(
        pile_id), starting_time=datetime.datetime.now(), user_id=id, complete="no")
    db.session.add(new_detail)
    db.session.commit()
    print(datetime.datetime.now(), "  ", user_name,
          "begin charging at pile", pile_id)
    return charging_duration


# 用户选择结束充电,type为指明是系统到时间触发的还是用户提前触发的,如果是充电桩故障,认为是用户触发
# 函数返回实际充电量和充电费用
def user_stop_charging(user_name, type):
    # 首先检查用户是否登录
    id = name_to_id(user_name)
    if id == 0:
        return [0, 0, 0]
    # 检查其state以及充电桩是否正常工作
    pile_id = 0
    car_information_list = get_value("car_information")
    # car_information = AllCarInformation()
    for i in car_information_list:
        if (i.get_user_id() == id and i.get_state() == 1):
            car_information = i
            pile_id = i.get_pile()  # 获得其充电桩编号
            break
    # 如果获得了pile_id,说明用户状态正确
    # 接下来检查充电桩状态
    pattern = ""
    if (pile_id == 0):
        return [0, 0, 0]
    if (pile_id == 1 or pile_id == 2):
        pattern = "F"
        speed = get_value("F_speed")
    else:
        pattern = "T"
        speed = get_value("T_speed")
    pile_state = 0
    charging_pile_state_list = get_value("charging_pile_state")
    # charging_pile_state = ChargingPileState()
    # for i in charging_pile_state_list:
    #     if(i.get_charging_pile_id() == pile_id):  # 找到充电桩
    #         charging_pile_state = i
    #         pile_state = i.get_proper_functioning()  # 获取充电桩状态
    #         if pile_state == 0:  # 没有正常工作
    #             return -1
    #         break
    # 检查完成,都是正确的,可以关闭充电了
    # car_information需要更改,充电详单信息表数据库需要完善一个表项,同时需要增加充电桩报表的数据库的一个表项,修改充电桩状态的内存表
    car_information.change_state(4)
    old_detail = ChargingDetail.query.filter(and_(ChargingDetail.charging_pile_id == str(
        pile_id), ChargingDetail.user_id == id, ChargingDetail.complete == "no"))

    starting_time = old_detail.first().starting_time
    # print(datetime.datetime.now(),"  ",starting_time)
    bill_time = datetime.datetime.now()
    if type == "system":
        charging_quantity = car_information.get_request_charging_quantity()
        charging_duration = (charging_quantity/speed)*3600  # 换算为秒
        stopping_time = starting_time + \
            datetime.timedelta(seconds=charging_duration)
    elif type == "user":
        stopping_time = datetime.datetime.now()
        charging_duration = (stopping_time-starting_time).seconds
        charging_quantity = charging_duration*speed/3600

    charging_cost = cost_of_charging(starting_time, stopping_time, pattern)
    service_cost = charging_quantity*get_value("unit_service_cost")
    total_cost = charging_cost+service_cost
    complete = "yes"
    old_detail.update(
        {"bill_time": bill_time, "charging_quantity": charging_quantity, "charging_duration": charging_duration, "stopping_time": stopping_time, "charging_cost": charging_cost, "service_cost": service_cost, "total_cost": total_cost, "complete": complete})
    db.session.commit()
    # 同时需要更新充电桩报表的数据库的一个表项
    # 首先找到这个充电桩
    charging_pile_report = ChargingPileReport.query.filter(
        ChargingPileReport.charging_pile_id == str(pile_id))
    # 然后更新就行
    # print(datetime.datetime.now(),"  ",charging_pile_report.first().cumulative_charging_times)
    cumulative_charging_times = charging_pile_report.first().cumulative_charging_times+1
    cumulative_charging_duration = charging_pile_report.first(
    ).cumulative_charging_duration+charging_duration
    accumulative_charging_quantity = charging_pile_report.first(
    ).accumulative_charging_quantity+charging_quantity
    accumulative_charging_cost = charging_pile_report.first(
    ).accumulative_charging_cost+charging_cost
    accumulative_service_cost = charging_pile_report.first(
    ).accumulative_service_cost+service_cost
    accumulative_total_cost = charging_pile_report.first().accumulative_total_cost + \
        total_cost
    showing_time = datetime.datetime.now()
    charging_pile_report.update(
        {"cumulative_charging_times": cumulative_charging_times, "cumulative_charging_duration": cumulative_charging_duration, "accumulative_charging_quantity": accumulative_charging_quantity, "accumulative_charging_cost": accumulative_charging_cost, "accumulative_service_cost": accumulative_service_cost, "accumulative_total_cost": accumulative_total_cost, "showing_time": showing_time})
    db.session.commit()

    # 修改充电桩状态的内存表
    charging_pile_state_list = get_value("charging_pile_state")
    # charging_pile_state = ChargingPileState()
    for i in charging_pile_state_list:
        if(i.get_charging_pile_id() == pile_id):  # 找到充电桩
            new_charging_times = i.get_cumulative_charging_times()+1
            new_charging_duration = i.get_cumulative_charging_duration()+charging_duration
            new_charging_quantity = i.get_accumulative_charging_quantity()+charging_quantity
            i.change_charging_info(
                new_charging_times, new_charging_duration, new_charging_quantity)
            break
    print(datetime.datetime.now(), "  ", user_name, "stop charging at", pile_id)
    return [charging_quantity, charging_cost, pile_id]


# 充电桩故障调度,两种调度方法
def pile_fault_priority(pile_id):
    # priority和time
    # 首先是优先级调度,优先为故障充电桩等候队列提供调度服务
    # 跟上面的请求排队号一样,如果对应的充电模式有空余,直接安排过去
    # 首先,我们结束当前充电,并生成一条充电详单,为此我们需要获得正在充电的用户id
    print(datetime.datetime.now(), "  ", "pile", pile_id, "is not working")
    # 需要注意的是,将坏的pile的里面的ID弹出
    pile_all = get_value("pile_car")
    pile_str = "pile"+str(pile_id)
    pile_all[pile_str] = []
    car_information_list = get_value("car_information")
    user_name = ""
    for i in car_information_list:
        if (i.get_pile() == pile_id and i.get_state() == 1):
            user_id = i.get_user_id()
            user_name = id_to_name(user_id)
            # print(datetime.datetime.now(),"  ","1: ",user_name)
            break
    # 如果user_name为空,说明没有车辆在充电,不需要生成详单,直接无调度或调度准备充电及排队的
    # print(datetime.datetime.now(),"  ","user_name:", user_name)
    # 不为空正常生成

    if (user_name != ""):
        # 这里我们调用结束充电的函数
        [charging_quantity, charging_cost, temp_pile_id] = user_stop_charging(
            user_name, "user")
        # print(datetime.datetime.now(),"  ","already charging quantity", charging_quantity)
        # 接下来,我们修改正在充电车辆和充电区等待车辆的状态,以及暂时修改等候区空间,同时修改充电车辆的请求充电量为其剩余的请求充电量
        ans = []
        ans_temp = []
        new_pile_id = 0
        new_state = 0
        new_pile_id_2 = 0
        new_state_2 = 0
        for i in car_information_list:
            if (i.get_pile() == pile_id):
                if (i.get_state() == 4 and i.get_user_id() == user_id):  # 之前正在充电的车
                    # i.change_state(3)
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 4")
                    user_name = id_to_name(i.get_user_id())
                    i.change_request_charging_quantity(
                        i.get_request_charging_quantity()-charging_quantity)
                    # 然后给他请求一个对应的充电桩

                    [new_pile_id, new_state] = find_pile(
                        user_name, i.get_request_charging_quantity(), i.get_pattern())
                    # 如果可以直接充电/进入充电区等待,我们就修改表中的state和pile_id,并返回给他安排的pile
                    # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
                    if(new_pile_id != 0 and new_pile_id != -1):  # 让ta直接移动到充电区
                        i.change_pile(new_pile_id)
                        i.change_state(new_state)
                        if (new_state == 5):
                            print(datetime.datetime.now(), "  ", "call", user_name,
                                  "to charging position,pile id is", new_pile_id)
                        elif(new_state == 2):
                            print(datetime.datetime.now(), "  ", "call", user_name,
                                  "to charging area,pile id is", new_pile_id)
                    elif (new_pile_id == -1):
                        # 虽然等候区没有空余,但我们认为它就在等候区
                        new_state = 3
                        new_pile_id = 0
                        i.change_pile(0)
                        i.change_state(new_state)
                        print(datetime.datetime.now(), "  ",
                              user_name, "keep in waiting area")
                    elif (new_pile_id == 0 and new_state == 3):
                        # 等候区有剩余,但我们不需要占用空间
                        i.change_pile(0)
                        i.change_state(3)
                        set_value(
                            "free_space", get_value("free_space")+1)
                        print(datetime.datetime.now(), "  ",
                              user_name, "keep in waiting area")
                    ans_temp = [user_name, new_pile_id, new_state]
                    ans.append(ans_temp)
                    ans_temp = []
                elif i.get_state() == 2:  # 充电区等候
                    new_pile_id_2 = 0
                    new_state_2 = 0
                    # 除了state外,信息不需要变动,直接给他找排队号
                    # 然后给他请求一个对应的充电桩
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 2")
                    user_name_2 = id_to_name(i.get_user_id())

                    [new_pile_id_2, new_state_2] = find_pile(
                        user_name_2, i.get_request_charging_quantity(), i.get_pattern())
                    if(new_pile_id_2 != 0 and new_pile_id_2 != -1):  # 让ta直接移动到充电区
                        i.change_pile(new_pile_id_2)
                        i.change_state(new_state_2)
                        if (new_state_2 == 5):
                            print(datetime.datetime.now(), "  ",
                                  "call", user_name_2, "to charging position,pile id is", new_pile_id_2)
                        elif(new_state_2 == 2):
                            print(datetime.datetime.now(), "  ", "call", user_name_2,
                                  "to new_pile_id_2 area,pile id is", new_pile_id_2)
                    elif (new_pile_id_2 == -1):
                        # 虽然等候区没有空余,但我们认为它就在等候区
                        new_state_2 = 3
                        new_pile_id_2 = 0
                        i.change_pile(0)
                        i.change_state(new_state_2)
                        print(datetime.datetime.now(), "  ",
                              user_name_2, "keep in waiting area")
                    elif (new_pile_id_2 == 0 and new_state_2 == 3):
                        # 等候区有剩余,但我们不需要占用空间
                        i.change_pile(0)
                        i.change_state(3)
                        set_value(
                            "free_space", get_value("free_space")+1)
                        print(datetime.datetime.now(), "  ",
                              user_name_2, "keep in waiting area")
                    ans_temp = [user_name_2, new_pile_id_2, new_state_2]
                    ans.append(ans_temp)
        # return [user_name, new_pile_id, new_state, user_name_2, new_pile_id_2, new_state_2]
        return ans
    elif (user_name == ""):
        # 没有车辆正在充电
        ans = []
        ans_temp = []
        user_name = ""
        new_pile_id = 0
        new_state = 0
        user_name_2 = ""
        new_pile_id_2 = 0
        new_state_2 = 0
        for i in car_information_list:
            if (i.get_pile() == pile_id):
                if (i.get_state() == 5):
                    print(datetime.datetime.now(), "  ",
                          "------", i.get_user_id(), " state 5")
                    user_name = id_to_name(i.get_user_id())
                    # print(datetime.datetime.now(),"  ","1: ", user_name)
                    new_pile_id = 0
                    new_state = 0
                    [new_pile_id, new_state] = find_pile(
                        user_name, i.get_request_charging_quantity(), i.get_pattern())
                    print(datetime.datetime.now(), "  ",
                          [new_pile_id, new_state])
                    # 如果可以直接充电/进入充电区等待,我们就修改表中的state和pile_id,并返回给他安排的pile
                    # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
                    if(new_pile_id != 0 and new_pile_id != -1):  # 让ta直接移动到充电区
                        i.change_pile(new_pile_id)
                        i.change_state(new_state)
                        if (new_state == 5):
                            print(datetime.datetime.now(), "  ", "call", user_name,
                                  "to charging position,pile id is", new_pile_id)
                        elif(new_state == 2):
                            print(datetime.datetime.now(), "  ", "call", user_name,
                                  "to charging area,pile id is", new_pile_id)
                    elif (new_pile_id == -1):
                        # 虽然等候区没有空余,但我们认为它就在等候区
                        new_state = 3
                        new_pile_id = 0
                        i.change_pile(0)
                        i.change_state(new_state)
                        print(datetime.datetime.now(), "  ",
                              user_name, "keep in waiting area")
                    elif (new_pile_id == 0 and new_state == 3):
                        # 等候区有剩余,但我们不需要占用空间,同时修改pile为0
                        i.change_pile(0)
                        i.change_state(3)
                        set_value(
                            "free_space", get_value("free_space")+1)
                        print(datetime.datetime.now(), "  ",
                              user_name, "keep in waiting area")
                    ans_temp = [user_name, new_pile_id, new_state]
                    ans.append(ans_temp)
                    ans_temp = []
                elif (i.get_state() == 2):  # 充电区等候
                    print(datetime.datetime.now(), "  ",
                          "------", i.get_user_id(), " state 2")
                    # 除了state外,信息不需要变动,直接给他找排队号
                    # 然后给他请求一个对应的充电桩
                    user_name_2 = id_to_name(i.get_user_id())
                    # print(datetime.datetime.now(),"  ","2: ", user_name_2)
                    new_pile_id_2 = 0
                    new_state_2 = 0
                    [new_pile_id_2, new_state_2] = find_pile(
                        user_name_2, i.get_request_charging_quantity(), i.get_pattern())
                    print(datetime.datetime.now(), "  ",
                          [new_pile_id_2, new_state_2])
                    if(new_pile_id_2 != 0 and new_pile_id_2 != -1):  # 让ta直接移动到充电区
                        i.change_pile(new_pile_id_2)
                        i.change_state(new_state_2)
                        if (new_state_2 == 5):
                            print(datetime.datetime.now(), "  ",
                                  "call", user_name_2, "to charging position,pile id is", new_pile_id_2)
                        elif(new_state_2 == 2):
                            print(datetime.datetime.now(), "  ", "call", user_name_2,
                                  "to new_pile_id_2 area,pile id is", new_pile_id_2)
                    elif (new_pile_id_2 == -1):
                        # 虽然等候区没有空余,但我们认为它就在等候区
                        i.change_pile(0)
                        new_state_2 = 3
                        new_pile_id_2 = 0
                        i.change_state(new_state_2)
                        print(datetime.datetime.now(), "  ",
                              user_name_2, "keep in waiting area")
                    elif (new_pile_id_2 == 0 and new_state_2 == 3):
                        # 等候区有剩余,但我们不需要占用空间
                        i.change_pile(0)
                        i.change_state(3)
                        set_value(
                            "free_space", get_value("free_space")+1)
                        print(datetime.datetime.now(), "  ",
                              user_name_2, "keep in waiting area")
                    ans_temp = [user_name_2, new_pile_id_2, new_state_2]
                    ans.append(ans_temp)
                    ans_temp = []
        # return [user_name, new_pile_id, new_state, user_name_2, new_pile_id_2, new_state_2]
        return ans


# 充电桩故障调度,两种调度方法
def pile_fault_time(pile_id):
    print(datetime.datetime.now(), "  ", "pile", pile_id, "is not working")
    # 需要注意的是,将坏的pile的里面的ID弹出
    pile_all = get_value("pile_car")
    pile_str = "pile"+str(pile_id)
    pile_all[pile_str] = []
    # 这里完成时间顺序调度
    if pile_id == 1 or pile_id == 2:
        pattern = "F"
    else:
        pattern = "T"
    car_information_list = get_value("car_information")
    user_name = ""
    for i in car_information_list:
        if (i.get_pile() == pile_id and i.get_state() == 1):
            user_id = i.get_user_id()
            user_name = id_to_name(user_id)
            # print(datetime.datetime.now(),"  ","1: ",user_name)
            break
    # 如果user_name为空,说明没有车辆在充电,不需要生成详单,直接无调度或调度准备充电及排队的
    print(datetime.datetime.now(), "  ", "user_name:", user_name)
    # 不为空正常生成
    if (user_name != ""):
        # 这里我们调用结束充电的函数
        [charging_quantity, charging_cost, temp_pile_id] = user_stop_charging(
            user_name, "user")
        print(datetime.datetime.now(), "  ",
              "already charging quantity", charging_quantity)
        # 接下来,我们修改正在充电车辆和充电区等待车辆的状态,以及暂时修改等候区空间,同时修改充电车辆的请求充电量为其剩余的请求充电量
        for i in car_information_list:
            if (i.get_pile() == pile_id):

                if (i.get_state() == 4 and i.get_user_id() == user_id):  # 之前正在充电的车
                    i.change_state(3)
                    i.change_pile(0)
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 4")
                    print(datetime.datetime.now(), "  ", "put",
                          user_name, "to waiting area temporarily")
                    user_name = id_to_name(i.get_user_id())
                    i.change_request_charging_quantity(
                        i.get_request_charging_quantity()-charging_quantity)
                elif i.get_state() == 2:  # 充电区等候
                    # 除了state外,信息不需要变动,直接给他找排队号

                    i.change_state(3)
                    i.change_pile(0)
                    print(datetime.datetime.now(), "  ", "put",
                          user_name, "to waiting area temporarily")
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 2")
    if (user_name == ""):
        for i in car_information_list:
            if (i.get_pile() == pile_id):
                if i.get_state() == 5:  # 之前准备充电的车
                    # i.change_state(3)
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 5")
                    i.change_state(3)
                    i.change_pile(0)
                    print(datetime.datetime.now(), "  ", "put", id_to_name(i.get_user_id()),
                          "to waiting area temporarily")
                elif i.get_state() == 2:  # 充电区等候
                    # 除了state外,信息不需要变动,直接给他找排队号
                    # 然后给他请求一个对应的充电桩
                    i.change_state(3)
                    i.change_pile(0)
                    print(datetime.datetime.now(), "  ", "put", id_to_name(i.get_user_id()),
                          "to waiting area temporarily")
                    # print(datetime.datetime.now(),"  ","------", i.get_user_id(), " state 2")
    # 然后我们找到这个模式的所有充电桩的充电区等待车辆,并把他们都修改为在等候区
    for i in car_information_list:
        if (i.get_pattern() == pattern and i.get_state() == 2):
            i.change_state(3)
            print(datetime.datetime.now(), "  ", "put", id_to_name(i.get_user_id()),
                  "to waiting area temporarily")
            # 还需要将他从队列中pop出来
            pile_str = "pile"+str(i.get_pile())
            pile_all[pile_str].remove(i.get_user_id())
            i.change_pile(0)
    # 此调度方法将所有充电区排队车辆放在一起进行调度

    new_pile_id = 0
    new_state = 0
    new_user_name = ""
    re_ans = []
    # 我们从头开始,依次find_pile
    for i in car_information_list:
        if (i.get_pattern() == pattern and i.get_state() == 3):
            new_user_id = i.get_user_id()
            new_user_name = id_to_name(new_user_id)
            [new_pile_id, new_state] = find_pile(
                new_user_name, i.get_request_charging_quantity(), i.get_pattern())
            # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
            if(new_pile_id != 0 and new_pile_id != -1):  # 让ta直接移动到充电区
                i.change_pile(new_pile_id)
                i.change_state(new_state)
                re_ans.append([new_user_id, new_pile_id, new_state])
                if (new_state == 5):
                    print(datetime.datetime.now(), "  ", "call", new_user_name,
                          "to charging position,pile id is", new_pile_id)
                elif(new_state == 2):
                    print(datetime.datetime.now(), "  ", "call", new_user_name,
                          "to charging area,pile id is", new_pile_id)
                re_ans.append([new_user_name, new_pile_id, new_state])
            elif (new_pile_id == -1):
                # 虽然等候区没有空余,但我们认为它就在等候区
                new_state = 3
                new_pile_id = 0
                i.change_pile(new_pile_id)
                i.change_state(new_state)
                print(datetime.datetime.now(), "  ",
                      new_user_name, "keep in waiting area")
                re_ans.append([new_user_name, new_pile_id, new_state])
            elif (new_pile_id == 0 and new_state == 3):
                # 等候区有剩余,但我们不需要占用空间
                new_state = 3
                new_pile_id = 0
                i.change_pile(0)
                i.change_state(3)
                print(datetime.datetime.now(), "  ",
                      new_user_name, "keep in waiting area")
                set_value(
                    "free_space", get_value("free_space")+1)
                re_ans.append([new_user_name, new_pile_id, new_state])
    return re_ans

# 充电桩回复正常


def pile_restore(pile_id):
    if pile_id == 1 or pile_id == 2:
        pattern = "F"
    else:
        pattern = "T"
    pile_all = get_value("pile_car")
    # 我们找到所有同类型充电桩充电区等待的车辆
    car_information_list = get_value("car_information")
    for i in car_information_list:
        if (i.get_pattern() == pattern and i.get_state() == 2):
            i.change_state(3)
            print(datetime.datetime.now(), "  ", "put", id_to_name(i.get_user_id()),
                  "to waiting area temporarily")
            # 还需要将他从队列中pop出来
            pile_str = "pile"+str(i.get_pile())
            pile_all[pile_str].pop()
            i.change_pile(0)
    new_pile_id = 0
    new_state = 0
    new_user_name = ""
    re_ans = []
    # 我们从头开始,依次find_pile
    for i in car_information_list:
        if (i.get_pattern() == pattern and i.get_state() == 3):
            new_user_id = i.get_user_id()
            new_user_name = id_to_name(new_user_id)
            [new_pile_id, new_state] = find_pile(
                new_user_name, i.get_request_charging_quantity(), i.get_pattern())
            # 00是未登录03是等候区有剩余-1-1是等候区没有空余15是准备充电12是充电区等待
            if(new_pile_id != 0 and new_pile_id != -1):  # 让ta直接移动到充电区
                i.change_pile(new_pile_id)
                i.change_state(new_state)
                if (new_state == 5):
                    print(datetime.datetime.now(), "  ", "call", new_user_name,
                          "to charging position,pile id is", new_pile_id)
                elif(new_state == 2):
                    print(datetime.datetime.now(), "  ", "call", new_user_name,
                          "to charging area,pile id is", new_pile_id)
                re_ans.append([new_user_name, new_pile_id, new_state])
            elif (new_pile_id == -1):
                # 虽然等候区没有空余,但我们认为它就在等候区
                new_state = 3
                new_pile_id = 0
                i.change_pile(new_pile_id)
                i.change_state(new_state)
                print(datetime.datetime.now(), "  ",
                      new_user_name, "keep in waiting area")
                re_ans.append([new_user_name, new_pile_id, new_state])
            elif (new_pile_id == 0 and new_state == 3):
                # 等候区有剩余,但我们不需要占用空间
                new_state = 3
                new_pile_id = 0
                i.change_pile(0)
                i.change_state(3)
                print(datetime.datetime.now(), "  ",
                      new_user_name, "keep in waiting area")
                set_value(
                    "free_space", get_value("free_space")+1)
                re_ans.append([new_user_name, new_pile_id, new_state])
    return re_ans

# 找到一个人ta的排队号X,X为TX,FX的X


def find_line_num(user_name, pattern):
    num = 0
    for i in get_value("car_information"):
        if(i.get_pattern() == pattern and i.get_state() == 3 and id_to_name(i.get_user_id()) != user_name):
            num += 1
        if (id_to_name(i.get_user_id()) == user_name):
            break
    return num

# 判单一个人是否下单


def judge_detail(user_name):
    for i in get_value("car_information"):
        if(id_to_name(i.get_user_id()) == user_name and i.get_state() != 4 and i.get_state() != 6):
            return 1
    return 0


# 获得真实的排队号
def get_true_line_num(user_name):
    for i in get_value("car_information"):
        if (id_to_name(i.get_user_id()) == user_name and i.get_state() != 4 and i.get_state() != 6):
            return i.get_line_number()
    return 0


def init_system(strategy):
    set_value("waiting_time", 5)
    set_value("strategy", strategy)  # 充电桩故障时调度策略,priority和time
    set_value("unit_service_cost", 0.8)
    set_value("user_log_in", [])  # 储存登录的用户的信息
    set_value("total_space", 6)  # 储存等候区空间大小
    set_value("free_space", get_value("total_space"))  # 储存等候区剩余空间大小
    set_value("car_information", [])  # 前来排过队的车辆信息

    set_value("pile_car", {"pile1": [], "pile2": [],
                           "pile3": [], "pile4": [], "pile5": []})
    # 初始化充电桩在本次系统启动期间的状态
    charging_pile_state = []
    for i in range(5):
        temp = ChargingPileState(i+1, 1, 0, 0, 0)
        charging_pile_state.append(temp)
    set_value("charging_pile_state",
              charging_pile_state)  # 充电桩在本次系统启动期间的状态

    # 删除之前存储的未完成订单的车辆的信息
    temp = ChargingDetail.query.filter(
        ChargingDetail.complete == "no").delete()
    db.session.commit()
